{
  "nbformat": 4,
  "nbformat_minor": 0,
  "metadata": {
    "colab": {
      "name": "dqn.ipynb",
      "provenance": [],
      "collapsed_sections": [],
      "authorship_tag": "ABX9TyOcxeZuqintpwn9JTs+YxVy",
      "include_colab_link": true
    },
    "kernelspec": {
      "name": "python3",
      "display_name": "Python 3"
    }
  },
  "cells": [
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "view-in-github",
        "colab_type": "text"
      },
      "source": [
        "<a href=\"https://colab.research.google.com/github/letianzj/QuantResearch/blob/master/ml/dqn.ipynb\" target=\"_parent\"><img src=\"https://colab.research.google.com/assets/colab-badge.svg\" alt=\"Open In Colab\"/></a>"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "JlNkxcEuDTVn",
        "colab_type": "text"
      },
      "source": [
        "## DQN CartPole\n",
        "\n",
        "Use deep q network to solve CartPole game.\n",
        "\n",
        "[OpenAI Gym CartPole](https://gym.openai.com/envs/CartPole-v0/) has four states, cart position, cart speed, pole angle, and pole speed. The actions are either going left or right. The objective is to keep pole from falling. Every move that doesn't lead to a fall gets reward 1.\n",
        "\n",
        "DQN is off policy, value based, TD method to solve control problems. In 2015, DeepMind used DQN to play 50 Atari games and was able to achieve human-level performance. It uses a DNN to model the q-value functions whose loss function is\n",
        "\n",
        "$$\n",
        "L = \\left( r+\\gamma \\underset{a' \\in A}{\\max}Q(s',a') - Q(s,a) \\right)^2  \\tag{1}\n",
        "$$\n",
        "\n",
        "DQN adds experience replay buffer and freezing target network to improve performance.\n",
        "\n",
        "This notebook follows closely [here](https://github.com/dragen1860/Deep-Learning-with-TensorFlow-book/blob/master/ch14-%E5%BC%BA%E5%8C%96%E5%AD%A6%E4%B9%A0/dqn_tf.py). Just added some comments for my own understanding.\n",
        "\n",
        "\n",
        "[Reference]\n",
        "* Sutton, Richard S., and Andrew G. Barto. Reinforcement learning: An introduction. MIT press, 2018.\n",
        "* [RL by David Silver](https://www.davidsilver.uk/teaching/)\n",
        "* [Lil'Log](https://lilianweng.github.io/lil-log/)\n",
        "* [Deep Learning with TensorFlow](https://github.com/dragen1860/Deep-Learning-with-TensorFlow-book)"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "0lOf7OSWHOvv",
        "colab_type": "code",
        "colab": {}
      },
      "source": [
        "import os\n",
        "import numpy as np\n",
        "import matplotlib.pyplot as plt\n",
        "import gym\n",
        "import collections\n",
        "import random\n",
        "import tensorflow as tf\n",
        "from tensorflow import keras"
      ],
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "xtBE-yWBHZZh",
        "colab_type": "code",
        "colab": {}
      },
      "source": [
        "env = gym.make('CartPole-v1')\n",
        "env.seed(1234)\n",
        "tf.random.set_seed(1234)\n",
        "np.random.seed(1234)"
      ],
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "6aJ__wslg1Vm",
        "colab_type": "code",
        "colab": {}
      },
      "source": [
        "# Hyperparameters\n",
        "episodes = 10000\n",
        "learning_rate = 0.0002\n",
        "gamma = 0.99\n",
        "buffer_limit = 50000\n",
        "batch_size = 32"
      ],
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "jbLHauFqg2C5",
        "colab_type": "code",
        "colab": {}
      },
      "source": [
        "class ReplayBuffer():\n",
        "    def __init__(self):\n",
        "        self.buffer = collections.deque(maxlen=buffer_limit)\n",
        "\n",
        "    def add_experience(self, transition):\n",
        "        self.buffer.append(transition)\n",
        "\n",
        "    def sample(self, n):\n",
        "        mini_batch = random.sample(self.buffer, n)\n",
        "        s_lst, a_lst, r_lst, s_prime_lst, done_mask_lst = [], [], [], [], []\n",
        "        for transition in mini_batch:\n",
        "            s, a, r, s_prime, done_mask = transition\n",
        "            s_lst.append(s)\n",
        "            a_lst.append([a])\n",
        "            r_lst.append([r])\n",
        "            s_prime_lst.append(s_prime)\n",
        "            done_mask_lst.append([done_mask])\n",
        "        # return Tensor\n",
        "        return tf.constant(s_lst, dtype=tf.float32),\\\n",
        "                      tf.constant(a_lst, dtype=tf.int32), \\\n",
        "                      tf.constant(r_lst, dtype=tf.float32), \\\n",
        "                      tf.constant(s_prime_lst, dtype=tf.float32), \\\n",
        "                      tf.constant(done_mask_lst, dtype=tf.float32)\n",
        "\n",
        "    def size(self):\n",
        "        return len(self.buffer)"
      ],
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "2xfhtwoNhHEu",
        "colab_type": "code",
        "colab": {}
      },
      "source": [
        "class DQN(keras.Model):\n",
        "    def __init__(self):\n",
        "        super(DQN, self).__init__()\n",
        "        self.fc1 = keras.layers.Dense(256, kernel_initializer='he_normal')\n",
        "        self.fc2 = keras.layers.Dense(256, kernel_initializer='he_normal')\n",
        "        self.fc3 = keras.layers.Dense(2, kernel_initializer='he_normal')\n",
        "\n",
        "    # input s, output Q value/logit\n",
        "    def call(self, x, training=None):\n",
        "        x = tf.nn.relu(self.fc1(x))\n",
        "        x = tf.nn.relu(self.fc2(x))\n",
        "        x = self.fc3(x)\n",
        "        return x\n",
        "\n",
        "    def get_action(self, s, epsilon):\n",
        "        s = tf.constant(s, dtype=tf.float32)        # to tensor\n",
        "        s = tf.expand_dims(s, axis=0)               # [4] => [1,4]\n",
        "        out = self(s)[0]                            # logits, shape = [1, 2]\n",
        "        coin = random.random()\n",
        "        # epsilon greedy\n",
        "        if coin < epsilon:\n",
        "            return random.randint(0, 1)\n",
        "        else:  # action with max Q value\n",
        "            return int(tf.argmax(out))\n",
        "\n",
        "\n",
        "def train(q, q_target, memory, optimizer):\n",
        "    # update Q-Net according to equation (1), keep target net constant\n",
        "    huber = keras.losses.Huber()\n",
        "    for i in range(10):  # train on some samples\n",
        "        # sample from replay buffer\n",
        "        s, a, r, s_prime, done_mask = memory.sample(batch_size)\n",
        "        with tf.GradientTape() as tape:\n",
        "            q_out = q(s)  # s: [b, 4] ==> [b, 2], Q(s,a)\n",
        "            # pick up q-value according to indices; a: [b, 1] action, indices: [b, 1];\n",
        "            indices = tf.expand_dims(tf.range(a.shape[0]), axis=1)\n",
        "            indices = tf.concat([indices, a], axis=1)       # [b, 2]; for every sample in the batch, which action is selected\n",
        "            q_a = tf.gather_nd(q_out, indices) # [b], Q(s, a) for actions chosen\n",
        "            q_a = tf.expand_dims(q_a, axis=1) # [b]=> [b,1]\n",
        "            # max Q(s',a) from target net,  [b,4]=>[b,2]=>[b,1]\n",
        "            max_q_prime = tf.reduce_max(q_target(s_prime),axis=1,keepdims=True)\n",
        "            # Q(s,a_t) target value based on Bellman equation\n",
        "            target = r + gamma * max_q_prime * done_mask\n",
        "            # Loss of equation (1)\n",
        "            loss = huber(q_a, target)\n",
        "\n",
        "        # Update Q-Net by minimizing Bellman loss\n",
        "        grads = tape.gradient(loss, q.trainable_variables)\n",
        "        optimizer.apply_gradients(zip(grads, q.trainable_variables))"
      ],
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "zhGLIwiAYsQ-",
        "colab_type": "code",
        "colab": {}
      },
      "source": [
        "q = DQN()\n",
        "q_target = DQN()\n",
        "q.build(input_shape=(2,4))\n",
        "q_target.build(input_shape=(2,4))\n",
        "for src, dest in zip(q.variables, q_target.variables):\n",
        "    dest.assign(src)     # q weights ==> q-target weights\n",
        "memory = ReplayBuffer()\n",
        "\n",
        "print_interval = 20\n",
        "score = 0.0\n",
        "avg_score = []\n",
        "optimizer = keras.optimizers.Adam(lr=learning_rate)\n",
        "\n",
        "for n_epi in range(episodes):\n",
        "    # epsilon decay\n",
        "    epsilon = max(0.01, 0.08 - 0.01 * (n_epi / 200))\n",
        "    s = env.reset()       # s is initial obs after reset\n",
        "    for t in range(600):  # run one episode\n",
        "        a = q.get_action(s, epsilon)\n",
        "        s_prime, r, done, info = env.step(a)\n",
        "        done_mask = 0.0 if done else 1.0\n",
        "        memory.add_experience((s, a, r / 100.0, s_prime, done_mask))\n",
        "        s = s_prime\n",
        "        score += r  # total return\n",
        "        if done:\n",
        "            break\n",
        "\n",
        "    if memory.size() > 2000:  # train as soon as there are 2000 experiences\n",
        "        train(q, q_target, memory, optimizer)\n",
        "\n",
        "    if n_epi % print_interval == 0 and n_epi != 0:\n",
        "        for src, dest in zip(q.variables, q_target.variables):\n",
        "            dest.assign(src)  # Update Target Net\n",
        "        # print(\"# of episode :{}, avg score : {:.1f}, buffer size : {}, \" \\\n",
        "        #       \"epsilon : {:.1f}%\" \\\n",
        "        #       .format(n_epi, score / print_interval, memory.size(), epsilon * 100))\n",
        "        avg_score.append(score / print_interval)\n",
        "        score = 0.0\n",
        "env.close()\n"
      ],
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "Z3Peln-Ru0rl",
        "colab_type": "code",
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 279
        },
        "outputId": "45eadeff-7d89-461a-d02c-9a83320b7b18"
      },
      "source": [
        "plt.plot(np.arange(len(avg_score)), avg_score)\n",
        "plt.plot(np.arange(len(avg_score)), avg_score, 's')\n",
        "plt.xlabel('epoch')\n",
        "plt.ylabel('avg score')\n",
        "plt.show()"
      ],
      "execution_count": null,
      "outputs": [
        {
          "output_type": "display_data",
          "data": {
            "image/png": "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\n",
            "text/plain": [
              "<Figure size 432x288 with 1 Axes>"
            ]
          },
          "metadata": {
            "tags": [],
            "needs_background": "light"
          }
        }
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "Wt-Iln8jKQ29",
        "colab_type": "code",
        "colab": {}
      },
      "source": [
        ""
      ],
      "execution_count": null,
      "outputs": []
    }
  ]
}